#include <aphw/Record.hpp>

#include <strings.h>

using namespace boost::python;

namespace aphw
{

struct GetRecord::Body
{
    Body() {
        bzero(&rec_, sizeof(ham_record_t));
    }

    ham_record_t rec_;
};

GetRecord::GetRecord() :
    body_ (new Body()) {}

ham_u32_t GetRecord::flags() const {
    assert(body_);
    return body_->rec_.flags;
}

ham_record_t* GetRecord::rec() {
    assert(body_);
    return &(body_->rec_);
}

object GetRecord::data()
{
    return object(
        handle<>(
            PyBuffer_FromReadWriteMemory(rec()->data, 
                                         rec()->size)));
}

class SetRecord::Body
{
public:
    Body(object buff)
        {
            bzero(&rec_, sizeof(ham_record_t));

            if (!PyObject_CheckBuffer(buff.ptr()))
            {
                PyErr_SetString(PyExc_TypeError,
                                "Record must be constructed with a buffer");
                throw_error_already_set();
            }
            
            if (PyObject_GetBuffer(buff.ptr(),
                                   &buff_,
                                   PyBUF_SIMPLE) != 0)
            {
                PyErr_SetString(PyExc_ValueError,
                                "Buffer object is invalid");
                throw_error_already_set();
            }
            
            rec_.size = buff_.len;
            rec_.data = buff_.buf;
            rec_.flags = 0;            
        }

    ~Body()
        {
            PyBuffer_Release(&buff_);            
        }

    ham_record_t rec_;

private:
    Py_buffer buff_;
};

SetRecord::SetRecord(object buff) :
    body_ (new Body(buff))
{}

ham_u32_t SetRecord::flags() const {
    assert(body_);
    return body_->rec_.flags;
}

ham_record_t* SetRecord::rec() {
    assert(body_);
    return &(body_->rec_);
}

void init_Record()
{
    class_<SetRecord>("SetRecord", init<object>())
        .add_property("flags", &SetRecord::flags)
        ;

    class_<GetRecord>("GetRecord", init<>())
        .add_property("flags", &GetRecord::flags)
        .add_property("data", &GetRecord::data)
        ;
}

}
